package server.core.manager;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import server.core.base.Airport;
import server.core.base.Flight;
import server.core.base.Ticket;
import server.core.dao.DaoFactory;
import server.core.dao.DaoFactory.daoType;
import server.core.util.FormatDate;

public class Guest extends Manager{
	
	public Guest(daoType type) {
		super(type);
	}

	/**
	 * @param from
	 * @param to
	 * @return Collection of Flights between two cities without date
	 */
	public Collection<Flight> getFlightByPorts(Airport from, Airport to) {
		Collection<Flight> portsCol = new LinkedList<Flight>();
		portsCol.clear();
		Set<?> entrySet = DaoFactory.getDao(typeOfDao).getEntityMap(Flight.class)
				.entrySet();
		Iterator<Map.Entry<Long, Flight>> itr = (Iterator<Entry<Long, Flight>>) entrySet
				.iterator();
		while (itr.hasNext()) {
			Map.Entry<Long, Flight> x = itr.next();
			if (from.equals(x.getValue().getFrom())
					& to.equals(x.getValue().getTo()))
				portsCol.add(x.getValue());
		}
		return portsCol;
	}

	/**
	 * @param d1
	 * @param M1
	 * @param y1
	 * @param H1
	 * @param m1
	 * @param d2
	 * @param M2
	 * @param y2
	 * @param H2
	 * @param m2
	 * @return Collection of Flights by dates without cities. Date is inputed as
	 *         integer
	 */
	public Collection<Flight> getFlightByDates(int d1, int M1, int y1, int H1,
			int m1, int d2, int M2, int y2, int H2, int m2) {
		Calendar date1 = new FormatDate(d1, M1, y1, H1, m1).getDate();
		Calendar date2 = new FormatDate(d2, M2, y2, H2, m2).getDate();
		return getFlightByDates(date1, date2);
	}

	/**
	 * @param date12
	 * @param date22
	 * @return Collection of Flights by dates without cities. Date is inputed as
	 *         Date.object
	 */
	public Collection<Flight> getFlightByDates(Date date1, Date date2) {
		Calendar date12 = new GregorianCalendar();
		date12.setTime(date1);
		Calendar date22 = new GregorianCalendar();
		date22.setTime(date2);
		return getFlightByDates(date12, date22);
	}

	/**
	 * @param date1
	 * @param date2
	 * @return Collection of Flights by dates without cities. Date is inputed as
	 *         object
	 */
	public Collection<Flight> getFlightByDates(Calendar date1,
			Calendar date2) {
		Collection<Flight> datesCol = new LinkedList<Flight>();
		datesCol.clear();
		Set<?> entrySet = DaoFactory.getDao(typeOfDao).getEntityMap(Flight.class)
				.entrySet();
		Iterator<Map.Entry<Long, Flight>> itr = (Iterator<Entry<Long, Flight>>) entrySet
				.iterator();
		while (itr.hasNext()) {
			Entry<Long, Flight> x = itr.next();
			if (date1.compareTo(x.getValue().getDepartureTime().getDate()) <= 0
					& date2.compareTo(
							x.getValue().getDepartureTime().getDate()) >= 0)
				datesCol.add(x.getValue());
		}
		return datesCol;
	}

	/**
	 * @param portsCol
	 * @param date1
	 * @param date2
	 * @return Collection of Flights by cities collection and two dates
	 */
	public Collection<Flight> getFlightByPortsDates(
			Collection<Flight> portsCol, Calendar date1, Calendar date2) {
		Collection<Flight> portsDatesCol = new LinkedList<Flight>();
		portsDatesCol.clear();
		if (portsCol==null)
			return getFlightByDates(date1, date2);
		else {
			Iterator<Flight> itr = portsCol.iterator();
			while (itr.hasNext()) {
				Flight x = itr.next();
				if (date1.compareTo(x.getDepartureTime().getDate()) <= 0
						& date2.compareTo(x.getDepartureTime().getDate()) >= 0)
					portsDatesCol.add(x);
			}
			return portsDatesCol;
		}
	}

	/**
	 * @param datesCol
	 * @param from
	 * @param to
	 * @return Collection of Flights by dates collection and two cities
	 */
	public Collection<Flight> getFlightByPortsDates(
			Collection<Flight> datesCol, Airport from, Airport to) {
		Collection<Flight> portsDatesCol = new LinkedList<Flight>();
		portsDatesCol.clear();
		if (datesCol==null)
			return getFlightByPorts(from, to);
		else {
			Iterator<Flight> itr = datesCol.iterator();
			while (itr.hasNext()) {
				Flight x = itr.next();
				if (from.equals(x.getFrom()) & to.equals(x.getTo()))
					portsDatesCol.add(x);
			}
			return portsDatesCol;
		}
	}

	/**
	 * @param from
	 * @param to
	 * @param date1
	 * @param date2
	 * @return Collection of Flights by two cities and two dates
	 */
	public Collection<Flight> searchFlight(Airport from, Airport to,
			Calendar date1, Calendar date2) {
		Collection<Flight> portsDatesCol =  new LinkedList<Flight>();
		portsDatesCol.clear();
		if (date1==null && date2==null)
			return getFlightByPorts(from, to);
		else if (from==null && to==null)
			return getFlightByDates(date1, date2);
		else
			return getFlightByPortsDates(getFlightByDates(date1, date2), from,
					to);
	}

	/**
	 * @param flight
	 * @return Collection of tickets by flight
	 */
	public Collection<Ticket> searchTicket(Flight flight) {
		LinkedList<Ticket> ticketsCol = new LinkedList<Ticket>();
		ticketsCol.clear();
		
		@SuppressWarnings("unchecked")
		Iterator<Ticket> itr=(Iterator<Ticket>) DaoFactory.getDao(typeOfDao).getEntityMap(Ticket.class).values().iterator();

		while (itr.hasNext()) {
			Ticket x = itr.next();
			if (flight.equals(x.getFlight()) & x.getCustomer()==null)
				
				// Add if first available or new price
//				if (ticketsCol.isEmpty() || x.getPrice() != ticketsCol.getLast().getPrice())
					ticketsCol.addLast(x);
		}
		return ticketsCol;
	}
	
	/**
	 * @param port1
	 * @param port2
	 * @param date1
	 * @param date2
	 * @return Collection of indirect flights between two airports with departure between two dates
	 */
	public Collection<Flight> getIndirectFlights(Airport port1, Airport port2,
			Calendar date1, Calendar date2){
		Iterator<Flight> itr1 = filterByDates(port1.getDepartureFlight(), date1, date2).iterator();
		Collection<Flight> connectCol = new LinkedList<Flight>();
		while (itr1.hasNext()) {
			Flight i = itr1.next();
			Iterator<Flight> itr2 = filterByDates(port2.getArrivalFlight(), date1, date2).iterator();

			while (itr2.hasNext()){
				Flight j = itr2.next();
				if(i.getTo().equals(j.getFrom())){
					connectCol.add(i);
					connectCol.add(j);
//					indirectCol.add(connectCol);
				}
			}
		}
		return connectCol;
	}
	
	public Collection<Flight> filterEqualsDate(Collection<Flight> flightCol, Calendar date1){
		Iterator<Flight> itr = flightCol.iterator();
		while(itr.hasNext())
			if( 0 < date1.compareTo(itr.next().getDepartureTime().getDate()))
				itr.remove();
		return flightCol;
	}
	
	public Collection<Flight> filterGreaterDate(Collection<Flight> flightCol, Calendar date1, Calendar rangeOfChange){
		Calendar date2=date1;
		date2.add(Calendar.HOUR_OF_DAY, rangeOfChange.get(Calendar.HOUR_OF_DAY));
		Iterator<Flight> itr = flightCol.iterator();
		while(itr.hasNext()){
			Flight x=itr.next();
			if(0>x.getDepartureTime().getDate().compareTo(date1)
					&&0<x.getDepartureTime().getDate().compareTo(date2))
				itr.remove();
		}
		return flightCol;
	}
	
	public Collection<Flight> filterByPorts(Collection<Flight> flightCol, Airport port1, Airport port2){
		if(flightCol==null)
			return getFlightByPorts(port1, port2);
		else{
			Iterator<Flight> itr = flightCol.iterator();
			while(itr.hasNext()){
				Flight x=itr.next();
				if(! port1.equals(x.getFrom())
						&& ! port2.equals(x.getTo()))
					itr.remove();
			}
		}
		return flightCol;
	}
	public Collection<Flight> filterByDates(Collection<Flight> flightCol, Calendar date1, Calendar date2){
		if(flightCol==null)
			return getFlightByDates(date1, date2);
		else{
			Collection<Flight> col = new LinkedList<Flight>();
			Iterator<Flight> itr = flightCol.iterator();
			while(itr.hasNext()){
				Flight x=itr.next();
				if(0>=date1.compareTo(x.getDepartureTime().getDate()) &
						0<=date2.compareTo(x.getDepartureTime().getDate()))
					col.add(x);
			}
			return col;
		}
	}

}
